/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月4日
 */
package com.massyframework.beanskin.runtime.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.runtime.service.filting.EmptyFilter;
import com.massyframework.beanskin.runtime.service.filting.LDAPFilterFactory;
import com.massyframework.beanskin.runtime.service.filting.ServiceTypeFilter;
import com.massyframework.beanskin.service.Filter;
import com.massyframework.beanskin.service.ServiceListener;
import com.massyframework.beanskin.service.ServiceNotFoundException;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.service.ServiceRegistry;
import com.massyframework.beanskin.service.ServiceRepository;



/**
 * {@link ServiceRepositoryDelegate} 代理{@link ServiceRepository}的请求，将处理转给{@link ServiceAdmin}处理
 */
final class ServiceRepositoryDelegate implements ServiceRepository {

    private final ServiceAdmin serviceAdmin;
    private final Module<?> module;

    /**
     * 构造方法
     * @param module {@link Module}, 装配件
     * @param serviceAdmin {@link ServiceAdmin}, 服务管理器
     */
    public ServiceRepositoryDelegate(Module<?> module, ServiceAdmin serviceAdmin) {
        this.serviceAdmin = Objects.requireNonNull(serviceAdmin, "\"serviceAdmin\" cannot be null");
        this.module =  Objects.requireNonNull(module, "\"module\" cannot be null");
    }

    /**
     * 添加事件监听器
     *
     * @param listener {@link ServiceListener}, 服务事件监听器
     */
    @Override
    public void addListener(ServiceListener listener) {
        this.addListener(listener, this.createFilter(null));
    }

    /**
     * 添加事件监听器和事件筛选器
     *
     * @param listener {@link ServiceListener}, 服务事件监听器
     * @param filter   {@link Filter}, 事件筛选器
     */
    @Override
    public void addListener(ServiceListener listener, Filter filter) {
        this.serviceAdmin.addListener(this.module, listener, filter);
    }

    /**
     * 使用筛选字符串创建筛选器<br>
     * 筛选字符串用于筛选关心的服务
     *
     * @param filterString 筛选字符串,可以为null,为null表示不对事件进行过滤处理
     * @return {@link Filter}
     */
    @Override
    public Filter createFilter(String filterString) {
        if (filterString == null){
            return EmptyFilter.getInstance();
        }
        return LDAPFilterFactory.newInstance(filterString);
    }

    /**
     * 使用<code>serviceType</code>和<code>filterString</code>创建筛选器
     *
     * @param serviceType  {@link Class}，服务类型
     * @param filterString {@link String}, 筛选字符串
     * @return {@link Filter}
     */
    @Override
    public Filter createFilter(Class<?> serviceType, String filterString) {
        Filter filter = this.createFilter(filterString);
        return new ServiceTypeFilter(serviceType, filter);
    }

    /**
     * 查找满足{@code filter}条件的首个服务
     *
     * @param serviceType {@link Class}, 服务类型
     * @param filter      {@link Filter}, 过滤器
     * @return {@link Optional}
     */
    @Override
    public <S> Optional<S> findService(Class<S> serviceType, Filter filter) {
        Optional<ServiceReference<S>> optionalService =
                this.findServiceReference(serviceType, filter);
        return optionalService.map(reference -> this.serviceAdmin.getService(reference, this.module));
    }

    /**
     * 根据{@code serviceType}和{@code filter}查找服务引用
     *
     * @param serviceType {@link Class},服务类型
     * @param filter      {@link Filter},过滤条件
     * @return {@link Optional}.
     */
    @Override
    public <S> Optional<ServiceReference<S>> findServiceReference(Class<S> serviceType, Filter filter) {
        ServiceReference<S> reference =
                this.serviceAdmin.findServiceReference(serviceType, filter, this.module);
        return reference == null ? Optional.empty() : Optional.of(reference);
    }

    /**
     * 获取类型为{@code serviceType}并满足{@code filter}的服务.
     * <p>
     * 当服务未找到时，抛出例外
     *
     * @param serviceType {@link Class},服务类型
     * @param filter      {@link Filter}, 过滤条件
     * @throws ServiceNotFoundException 服务不存在时抛出的例外
     */
    @Override
    public <S> S getService(Class<S> serviceType, Filter filter) throws ServiceNotFoundException {
        Optional<S> result = this.findService(serviceType, filter);
        return result.orElseThrow(
                () -> new ServiceNotFoundException("cannot found service: serviceType=" + serviceType + "."));
    }

    /**
     * 所有满足{@code filter}的{@code serviceType}类型的服务
     *
     * @param serviceType {@link Class}, 服务类型
     * @param filter      {@link Filter}, 过滤器
     * @return {@link List}
     */
    @Override
    public <S> List<S> getServices(Class<S> serviceType, Filter filter) {
        List<ServiceReference<S>> references =
                this.serviceAdmin.getServiceReferences(serviceType, filter, this.module);
        List<S> result = new ArrayList<S>();
        for (ServiceReference<S> reference: references){
            S service = this.serviceAdmin.getService(reference, this.module);
            if (service != null){
                result.add(service);
            }
        }
        return result;
    }

    /**
     * 所有服务类型
     *
     * @return {@link List}
     */
    @Override
    public List<Class<?>> getServiceTypes() {
        return this.serviceAdmin.getServiceTypes();
    }

    /**
     * 使用{@code reference}定位服务，并使用
     * <p>
     * 可能因为服务同时被卸载，导致{@code reference}引用的服务不存在，这种情况下会抛出服务未找到例外
     *
     * @param reference {@link ServiceReference}, 服务引用
     * @throws ServiceNotFoundException 服务不存在时抛出的例外
     */
    @Override
    public <S> Optional<S> getService(ServiceReference<S> reference) throws ServiceNotFoundException {
        S result = this.serviceAdmin.getService(reference, this.module);
        return Optional.ofNullable(result);
    }


    /**
     * 获取{@code serviceType}类型并满足{@code filterString}条件的所有服务引用
     *
     * @param serviceType {@link Class},服务类型
     * @param filter      过滤条件
     * @return {@link List}.
     */
    @Override
    public <S> List<ServiceReference<S>> getServiceReferences(Class<S> serviceType, Filter filter) {
        return this.serviceAdmin.getServiceReferences(serviceType, filter, this.module);
    }

    /**
     * 获取满足{@code filter}的所有服务引用
     *
     * @param filter {@link Filter},过滤条件
     * @return {@link List}
     */
    @Override
    public List<ServiceReference<?>> getServiceReferences(Filter filter) {
        return this.serviceAdmin.getServiceReferences(filter, this.module);
    }

    /**
     * 服务注册器
     *
     * @return {@link ServiceRegistry}
     */
    @Override
    public ServiceRegistry getServiceRegistry() {
        return this.serviceAdmin.getServiceRegistry(this.module);
    }

    /**
     * 移除事件监听器
     *
     * @param listener {@link ServiceListener}, 服务事件监听器
     */
    @Override
    public void removeListener(ServiceListener listener) {
        this.serviceAdmin.removeListener(this.module, listener);
    }

}

